#include <sstream>
#include <iomanip>

#include "base_util/utils.h"
#include "det_predictor.h"
#include <opencv2/dnn.hpp>

namespace ai {


static void dump_tensor_attr(rknn_tensor_attr *attr) {
  printf("  index=%d, name=%s, n_dims=%d, dims=[%d, %d, %d, %d], n_elems=%d, size=%d, fmt=%s, type=%s, qnt_type=%s, "
          "zp=%d, scale=%f\n",
          attr->index, attr->name, attr->n_dims, attr->dims[0], attr->dims[1], attr->dims[2], attr->dims[3],
          attr->n_elems, attr->size, get_format_string(attr->fmt), get_type_string(attr->type),
          get_qnt_type_string(attr->qnt_type), attr->zp, attr->scale);
}
static inline float fast_exp(float x) {
  // return exp(x);
  union
  {
    uint32_t i;
    float f;
  } v;
  v.i = (12102203.1616540672 * x + 1064807160.56887296);
  return v.f;
}
static float DeQnt2F32(int8_t qnt, int zp, float scale) {
  return ((float)qnt - (float)zp) * scale;
}

RKDetPredictor::RKDetPredictor(RKPackPredictor* model, RKModelManager* manager, LogInfo *lg):
  RKPredictor(model, manager, lg) { }


int RKDetPredictor::start_postprocess_thread_imp() {
  int ret = 0;
  std::pair<std::pair<int,int>,int> cur_block;
  // stop_flag2 = common::CameraGrabing;
  // while (stop_flag2 == common::CameraGrabing) {

  //   run_mtx2.lock();
  //   if (post_data2.empty()) {run_mtx2.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(3));continue;}
  //   cur_block = post_data2.front();
  //   post_data2.pop();
  //   run_mtx2.unlock();

  //   int loop_idx = cur_block.first.second;
  //   std::vector<BaseInfo*> det_infos;
  //   ret = det_hb_->PostProcess(det_infos, cur_block.first.first, this, cur_block.second);  //处理图片
  //   run_mtx3.lock();
  //   out_data3[loop_idx].push(det_infos);  //将处理后的数据返回到det_infos,加入队列中
  //   run_mtx3.unlock();
  // }
  // stop_flag2 = common::CameraOpened;
  return 0;
}

int RKDetPredictor::RunDet(stream::ImageBlob* blob, std::vector<BaseInfo*>& det_infos) {
  int ret;

  stream::ImageBlob img_blob(stream::ImageBlobMode_BGR);
  if (!mdl_rk->cfg->transforms->run(blob->img, img_blob, mdl_rk->cfg)) { 
    printf("transforms->run fail \n");
    return model_image_channels_check_error;
  }
  // std::cout << "img_blob.img w:" << img_blob.img.cols << " h:" << img_blob.img.rows << std::endl;
  rknn_tensor_attr output_attrs[mdl_rk->output_count];
  memset(output_attrs, 0, sizeof(output_attrs));
  for (int i = 0; i < mdl_rk->output_count; i++) {
    output_attrs[i].index = i;
    ret = rknn_query(mdl_rk->ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
    // dump_tensor_attr(&(output_attrs[i]));
  }

  mdl_rk->inputs[0].buf = (void *)(img_blob.img.data);
  rknn_inputs_set(mdl_rk->ctx, mdl_rk->input_count, &mdl_rk->inputs[0]);

  rknn_core_mask core_mask = RKNN_NPU_CORE_0;
  if(mdl_rk->cfg->gpu_id==1) { core_mask = RKNN_NPU_CORE_1; }
  if(mdl_rk->cfg->gpu_id==2) { core_mask = RKNN_NPU_CORE_2; }
  ret = rknn_set_core_mask(mdl_rk->ctx, core_mask);
  ret = rknn_run(mdl_rk->ctx, NULL);
  if (ret != 0) {printf("rknn_run fail %d", ret); return -1;}
  ret = rknn_outputs_get(mdl_rk->ctx, mdl_rk->output_count, &mdl_rk->outputs[0], NULL);
  if (ret != 0) {printf("rknn_outputs_get fail %d", ret); return -1;}
 
  // 后处理部分
  std::vector<float> out_scales;
  std::vector<int32_t> out_zps;
  for (int i = 0; i < mdl_rk->output_count; ++i) {
    out_scales.push_back(output_attrs[i].scale);
    out_zps.push_back(output_attrs[i].zp);
  }

  // 1类输出的onnx模型转rknn
  if (mdl_rk->cfg->arch == "YOLOV8.out1") {
    GetConvDetectionResult_out1(img_blob, output_attrs, det_infos);
  } 
  // 6类输出的onnx模型转rknn
  else {
    GetConvDetectionResult(img_blob, out_zps, out_scales, det_infos);
  }
  rknn_outputs_release(mdl_rk->ctx, mdl_rk->output_count, &mdl_rk->outputs[0]);

  return 0;

}



float RKDetPredictor::sigmoid(float x)
{
    return 1 / (1 + fast_exp(-x));
}

int RKDetPredictor::GenerateMeshGrid() {
  int ret = 0;
  HeadNum = mdl_rk->cfg->map_size.size();

  for (int index = 0; index < HeadNum; index++) {
    for (int i = 0; i < mdl_rk->cfg->map_size[index][0]; i++) {
      for (int j = 0; j < mdl_rk->cfg->map_size[index][1]; j++) {
        MeshGrid.push_back(float(j + 0.5));
        MeshGrid.push_back(float(i + 0.5));
      }
    }
  }
  return ret;
}

inline static int32_t __clip(float val, float min, float max)
{
    float f = val <= min ? min : (val >= max ? max : val);
    return f;
}
static int8_t qnt_f32_to_affine(float f32, int32_t zp, float scale)
{
    float dst_val = (f32 / scale) + zp;
    int8_t res = (int8_t)__clip(dst_val, -128, 127);
    return res;
}
static float deqnt_affine_to_f32(int8_t qnt, int32_t zp, float scale) { return ((float)qnt - (float)zp) * scale; }


static void compute_dfl(float* tensor, int dfl_len, float* box){
    for (int b=0; b<4; b++){
        float exp_t[dfl_len];
        float exp_sum=0;
        float acc_sum=0;
        for (int i=0; i< dfl_len; i++){
            exp_t[i] = exp(tensor[i+b*dfl_len]);
            exp_sum += exp_t[i];
        }
        
        for (int i=0; i< dfl_len; i++){
            acc_sum += exp_t[i]/exp_sum *i;
        }
        box[b] = acc_sum;
    }
}

static int process_i8(int8_t *box_tensor, int32_t box_zp, float box_scale,
                      int8_t *score_tensor, int32_t score_zp, float score_scale,
                      int8_t *score_sum_tensor, int32_t score_sum_zp, float score_sum_scale,
                      int grid_h, int grid_w, int stride, int dfl_len,
                      std::vector<float> &boxes, 
                      std::vector<float> &objProbs, 
                      std::vector<int> &classId, 
                      float threshold, int class_num)
{
    int validCount = 0;
    int grid_len = grid_h * grid_w;
    int8_t score_thres_i8 = qnt_f32_to_affine(threshold, score_zp, score_scale);
    int8_t score_sum_thres_i8 = qnt_f32_to_affine(threshold, score_sum_zp, score_sum_scale);

    for (int i = 0; i < grid_h; i++)
    {
        for (int j = 0; j < grid_w; j++)
        {
            int offset = i* grid_w + j;
            int max_class_id = -1;

            // 通过 score sum 起到快速过滤的作用
            if (score_sum_tensor != nullptr){
                if (score_sum_tensor[offset] < score_sum_thres_i8){
                    continue;
                }
            }

            int8_t max_score = -score_zp;
            for (int c= 0; c< class_num; c++){
                if ((score_tensor[offset] > score_thres_i8) && (score_tensor[offset] > max_score))
                {
                    max_score = score_tensor[offset];
                    max_class_id = c;
                }
                offset += grid_len;
            }

            // compute box
            if (max_score> score_thres_i8){
                offset = i* grid_w + j;
                float box[4];
                float before_dfl[dfl_len*4];
                for (int k=0; k< dfl_len*4; k++){
                    before_dfl[k] = deqnt_affine_to_f32(box_tensor[offset], box_zp, box_scale);
                    offset += grid_len;
                }
                compute_dfl(before_dfl, dfl_len, box);

                float x1,y1,x2,y2,w,h;
                x1 = (-box[0] + j + 0.5)*stride;
                y1 = (-box[1] + i + 0.5)*stride;
                x2 = (box[2] + j + 0.5)*stride;
                y2 = (box[3] + i + 0.5)*stride;
                w = x2 - x1;
                h = y2 - y1;
                boxes.push_back(x1);
                boxes.push_back(y1);
                boxes.push_back(w);
                boxes.push_back(h);

                objProbs.push_back(deqnt_affine_to_f32(max_score, score_zp, score_scale));
                classId.push_back(max_class_id);
                validCount ++;
            }
        }
    }
    return validCount;
}

static int quick_sort_indice_inverse(std::vector<float> &input, int left, int right, std::vector<int> &indices)
{
    float key;
    int key_index;
    int low = left;
    int high = right;
    if (left < right)
    {
        key_index = indices[left];
        key = input[left];
        while (low < high)
        {
            while (low < high && input[high] <= key)
            {
                high--;
            }
            input[low] = input[high];
            indices[low] = indices[high];
            while (low < high && input[low] >= key)
            {
                low++;
            }
            input[high] = input[low];
            indices[high] = indices[low];
        }
        input[low] = key;
        indices[low] = key_index;
        quick_sort_indice_inverse(input, left, low - 1, indices);
        quick_sort_indice_inverse(input, low + 1, right, indices);
    }
    return low;
}
static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0, float xmin1, float ymin1, float xmax1,
                              float ymax1)
{
    float w = fmax(0.f, fmin(xmax0, xmax1) - fmax(xmin0, xmin1) + 1.0);
    float h = fmax(0.f, fmin(ymax0, ymax1) - fmax(ymin0, ymin1) + 1.0);
    float i = w * h;
    float u = (xmax0 - xmin0 + 1.0) * (ymax0 - ymin0 + 1.0) + (xmax1 - xmin1 + 1.0) * (ymax1 - ymin1 + 1.0) - i;
    return u <= 0.f ? 0.f : (i / u);
}
static int nms(int validCount, std::vector<float> &outputLocations, std::vector<int> classIds, std::vector<int> &order,
               int filterId, float threshold)
{
    for (int i = 0; i < validCount; ++i)
    {
        if (order[i] == -1 || classIds[i] != filterId)
        {
            continue;
        }
        int n = order[i];
        for (int j = i + 1; j < validCount; ++j)
        {
            int m = order[j];
            if (m == -1 || classIds[i] != filterId)
            {
                continue;
            }
            float xmin0 = outputLocations[n * 4 + 0];
            float ymin0 = outputLocations[n * 4 + 1];
            float xmax0 = outputLocations[n * 4 + 0] + outputLocations[n * 4 + 2];
            float ymax0 = outputLocations[n * 4 + 1] + outputLocations[n * 4 + 3];

            float xmin1 = outputLocations[m * 4 + 0];
            float ymin1 = outputLocations[m * 4 + 1];
            float xmax1 = outputLocations[m * 4 + 0] + outputLocations[m * 4 + 2];
            float ymax1 = outputLocations[m * 4 + 1] + outputLocations[m * 4 + 3];

            float iou = CalculateOverlap(xmin0, ymin0, xmax0, ymax0, xmin1, ymin1, xmax1, ymax1);

            if (iou > threshold)
            {
                order[j] = -1;
            }
        }
    }
    return 0;
}
int RKDetPredictor::GetConvDetectionResult_out1(stream::ImageBlob& img_blob, rknn_tensor_attr* output_attrs, std::vector<BaseInfo*>& det_infos) {
  int ret = 0;

  std::vector<float> filterBoxes;
  std::vector<float> objProbs;
  std::vector<int> classId;
  int validCount = 0;
  int stride = 0;
  int grid_h = 0;
  int grid_w = 0;
  int class_num = mdl_rk->cfg->label_list.size();


  int dfl_len = output_attrs[0].dims[1] /4;
  int output_per_branch = mdl_rk->output_count / 3;
  for (int i = 0; i < 3; i++)
  {
      void *score_sum = nullptr;
      int32_t score_sum_zp = 0;
      float score_sum_scale = 1.0;
      if (output_per_branch == 3){
          score_sum = mdl_rk->outputs[i*output_per_branch + 2].buf;
          score_sum_zp = output_attrs[i*output_per_branch + 2].zp;
          score_sum_scale = output_attrs[i*output_per_branch + 2].scale;
      }
      int box_idx = i*output_per_branch;
      int score_idx = i*output_per_branch + 1;


      grid_h = output_attrs[box_idx].dims[2];
      grid_w = output_attrs[box_idx].dims[3];
      stride = mdl_rk->cfg->input_shape[0] / grid_h;

      if (1)
      {

          validCount += process_i8((int8_t *)mdl_rk->outputs[box_idx].buf, output_attrs[box_idx].zp, output_attrs[box_idx].scale,
                                    (int8_t *)mdl_rk->outputs[score_idx].buf, output_attrs[score_idx].zp, output_attrs[score_idx].scale,
                                    (int8_t *)score_sum, score_sum_zp, score_sum_scale,
                                    grid_h, grid_w, stride, dfl_len, 
                                    filterBoxes, objProbs, classId, mdl_rk->cfg->draw_threshold, class_num);
      }
      else
      {
          // validCount += process_fp32((float *)mdl_rk->outputs[box_idx].buf, (float *)mdl_rk->outputs[score_idx].buf, (float *)score_sum,
          //                             grid_h, grid_w, stride, dfl_len, 
          //                             filterBoxes, objProbs, classId, mdl_rk->cfg->draw_threshold);
      }
  }

  // no object detect
  if (validCount <= 0)
  {
      return 0;
  }
  std::vector<int> indexArray;
  for (int i = 0; i < validCount; ++i)
  {
      indexArray.push_back(i);
  }
  quick_sort_indice_inverse(objProbs, 0, validCount - 1, indexArray);

  std::set<int> class_set(std::begin(classId), std::end(classId));

  for (auto c : class_set)
  {
      nms(validCount, filterBoxes, classId, indexArray, c, mdl_rk->cfg->nms_threshold);
  }


  /* box valid detect target */
  for (int i = 0; i < validCount; ++i)
  {
      if (indexArray[i] == -1)
      {
          continue;
      }
      int n = indexArray[i];

      float x1 = filterBoxes[n * 4 + 0] / img_blob.scale;  //  - letter_box->x_pad
      float y1 = filterBoxes[n * 4 + 1] / img_blob.scale;  //  - letter_box->y_pad
      float x2 = x1 + filterBoxes[n * 4 + 2] / img_blob.scale;
      float y2 = y1 + filterBoxes[n * 4 + 3] / img_blob.scale;

      x1 = x1 > 0 ? x1 : 0;
      y1 = y1 > 0 ? y1 : 0;
      x2 = x2 < img_blob.ori_im_shape[1] ? x2 : img_blob.ori_im_shape[1];
      y2 = y2 < img_blob.ori_im_shape[0] ? y2 : img_blob.ori_im_shape[0];


      int id = classId[n];
      float obj_conf = objProbs[i];

      DetInfo* di = new DetInfo(objProbs[i], classId[n], cv::Rect(x1,y1,x2-x1,y2-y1), mdl_rk->cfg->label_list[classId[n]]);
      det_infos.emplace_back(di);

  }
  return 0;




  // std::vector<int> indices;
  // if (mdl_rk->cfg->arch == "YOLOV8") {
  //   cv::dnn::NMSBoxes(boxs, confidences, mdl_rk->cfg->draw_threshold, mdl_rk->cfg->nms_threshold, indices, 100);
  // }


  return ret;
}

int RKDetPredictor::GetConvDetectionResult(stream::ImageBlob& img_blob, std::vector<int> &qnt_zp, std::vector<float> &qnt_scale, std::vector<BaseInfo*>& det_infos) {
  int ret = 0;
  if (MeshGrid.empty()) { ret = GenerateMeshGrid(); }

  std::vector<cv::Rect> boxs;
  std::vector<float> confidences;
  std::vector<int> labels;

  std::vector<float> RegDfl;
  std::vector<float> RegDeq(16, 0);
  int gridIndex = -2;
  float xmin = 0, ymin = 0, xmax = 0, ymax = 0;
  float cls_val = 0;
  float cls_max = 0;
  int cls_index = 0;
  int class_num = mdl_rk->cfg->label_list.size();
  int quant_zp_cls = 0, quant_zp_reg = 0, quant_zp_msk;
  float quant_scale_cls = 0, quant_scale_reg = 0, quant_scale_msk = 0;
  auto& Strides = mdl_rk->cfg->strides;
  auto& MapSize = mdl_rk->cfg->map_size;
  
  for (int index = 0; index < HeadNum; index++) {
    int8_t *reg = (int8_t *)mdl_rk->outputs[index * 2 + 0].buf;
    int8_t *cls = (int8_t *)mdl_rk->outputs[index * 2 + 1].buf;
    int8_t *msk = (int8_t *)mdl_rk->outputs[index + HeadNum * 2].buf;

    quant_zp_reg = qnt_zp[index * 2 + 0];
    quant_zp_cls = qnt_zp[index * 2 + 1];
    quant_zp_msk = qnt_zp[index + HeadNum * 2];

    quant_scale_reg = qnt_scale[index * 2 + 0];
    quant_scale_cls = qnt_scale[index * 2 + 1];
    quant_scale_msk = qnt_scale[index + HeadNum * 2];

    float sfsum = 0;
    float locval = 0;
    float locvaltemp = 0;

    for (int h = 0; h < MapSize[index][0]; h++) {
      for (int w = 0; w < MapSize[index][1]; w++) {
        gridIndex += 2;
        if (1 == class_num) {
          cls_max = sigmoid(DeQnt2F32(cls[0 * MapSize[index][0] * MapSize[index][1] + h * MapSize[index][1] + w], quant_zp_cls, quant_scale_cls));
          cls_index = 0;
        } else {
          for (int cl = 0; cl < class_num; cl++) {
            cls_val = cls[cl * MapSize[index][0] * MapSize[index][1] + h * MapSize[index][1] + w];

            if (0 == cl) {
              cls_max = cls_val;
              cls_index = cl;
            } else {
              if (cls_val > cls_max) {
                cls_max = cls_val;
                cls_index = cl;
              }
            }
          }
          cls_max = sigmoid(DeQnt2F32(cls_max, quant_zp_cls, quant_scale_cls));
        }

        if (cls_max < mdl_rk->cfg->draw_threshold) {continue;}

        RegDfl.clear();
        for (int lc = 0; lc < 4; lc++) {
          sfsum = 0;
          locval = 0;
          for (int df = 0; df < 16; df++) {
            locvaltemp = exp(DeQnt2F32(reg[((lc * 16) + df) * MapSize[index][0] * MapSize[index][1] + h * MapSize[index][1] + w], quant_zp_reg, quant_scale_reg));
            RegDeq[df] = locvaltemp;
            sfsum += locvaltemp;
          }
          for (int df = 0; df < 16; df++) {
            locvaltemp = RegDeq[df] / sfsum;
            locval += locvaltemp * df;
          }

          RegDfl.push_back(locval);
        }

        xmin = (MeshGrid[gridIndex + 0] - RegDfl[0]) * Strides[index] / img_blob.scale;
        ymin = (MeshGrid[gridIndex + 1] - RegDfl[1]) * Strides[index] / img_blob.scale;
        xmax = (MeshGrid[gridIndex + 0] + RegDfl[2]) * Strides[index] / img_blob.scale;
        ymax = (MeshGrid[gridIndex + 1] + RegDfl[3]) * Strides[index] / img_blob.scale;
        // std::cout << "cls_max: " << cls_max << " xmin: " << xmin << " ymin: " << ymin << " xmax: " << xmax << " ymax: " << ymax << std::endl;

        xmin = xmin > 0 ? xmin : 0;
        ymin = ymin > 0 ? ymin : 0;
        xmax = xmax < img_blob.ori_im_shape[1] ? xmax : img_blob.ori_im_shape[1];
        ymax = ymax < img_blob.ori_im_shape[0] ? ymax : img_blob.ori_im_shape[0];

        labels.push_back(cls_index);
        confidences.push_back(cls_max);
        boxs.push_back(cv::Rect(xmin, ymin, xmax-xmin, ymax-ymin));
      }
    }
  }

  std::vector<int> indices;
  if (mdl_rk->cfg->arch == "YOLOV8") {
    cv::dnn::NMSBoxes(boxs, confidences, mdl_rk->cfg->draw_threshold, mdl_rk->cfg->nms_threshold, indices, 100);
  }
  // V10 不需要nms
  if (mdl_rk->cfg->arch == "YOLOV10") {
    for (int idx=0; idx < boxs.size(); idx++) {indices.push_back(idx);}
  }

  for (auto& idx : indices) {
    DetInfo* di = new DetInfo(confidences[idx], labels[idx], boxs[idx], mdl_rk->cfg->label_list[labels[idx]]);
    det_infos.emplace_back(di);
  }

  // if (det_infos.size() > TopK) {
  //   std::sort(det_infos.begin(), det_infos.end(), [](ai::BaseInfo* &Rect1, ai::BaseInfo* &Rect2) -> bool { return (Rect1->score > Rect2->score); });
  //   for (auto it = det_infos.begin() + TopK; it != det_infos.end();) {
  //     delete *it;
  //     it = det_infos.erase(it);
  //   }
  // }

  return ret;
}

int RKDetPredictor::PostProcess(std::vector<BaseInfo*>& det_infos, 
                int cur_block,
                RKModelManager* mng, 
                int md_idx) {

  return 0;
}

void RKDetPredictor::ParseTensor(float* data, int layer, 
  std::vector<cv::Rect>& boxs, std::vector<float>& scores, std::vector<int>& labels,
  std::vector<int> ori_shape, std::vector<int> feteature_shape, ModelConfig* cfg) {
    int num_classes = cfg->label_list.size();
    int stride = cfg->strides[layer];
    int num_pred = num_classes + 4 + 1;
    if (cfg->anchors_table.empty()) {
      spdlog::get("logger")->info("ERROR. RKDetPredictor::ParseTensor anchors_table is empty.");
      return;
    }
    std::vector<std::vector<int>> &anchors = cfg->anchors_table[layer];
    float w_scale = ori_shape[1] * 1.0 / cfg->input_shape[1];
    float h_scale = ori_shape[0] * 1.0 / cfg->input_shape[0];
    // spdlog::get("logger")->info("num_classes: {}, stride: {}, num_pred: {}, w_scale: {}, h_scale: {}", num_classes, stride, num_pred, w_scale, h_scale);

    int anchor_num = anchors.size();
    for (int h = 0; h < feteature_shape[0]; h++) {
      for (int w = 0; w < feteature_shape[1]; w++) {
        for (int k = 0; k < anchor_num; k++) {
          float *cur_data = data + k * num_pred;
          // if (h == 0 && w == 0 ) {printf("%f, %f, %f, %f, %f, %f, %f, %f\n", cur_data[0],cur_data[1],cur_data[2],cur_data[3],cur_data[4],cur_data[5],cur_data[6],cur_data[7]);}
          
          int id = std::distance(cur_data + 5, std::max_element(cur_data + 5, cur_data + 5 + num_classes));
          double x1 = 1 / (1 + std::exp(-cur_data[4])) * 1;
          double x2 = 1 / (1 + std::exp(-cur_data[id + 5]));
          double confidence = x1 * x2;
          // if (1 ) {printf("id:%d, 4:%f, id+5:%f, x1:%f, x2:%f, confidence:%f\n", id, cur_data[4], cur_data[id + 5], x1, x2, confidence);}
          if (confidence < cfg->draw_threshold) {continue;}
          // spdlog::get("logger")->info("confidence:{}", confidence);

          double cx = ((1.0 / (1.0 + std::exp(-cur_data[0]))) * 2 - 0.5 + w) * stride;
          double cy = ((1.0 / (1.0 + std::exp(-cur_data[1]))) * 2 - 0.5 + h) * stride;
          double ww = std::pow((1.0 / (1.0 + std::exp(-cur_data[2]))) * 2, 2) * anchors[k][0];
          double hh = std::pow((1.0 / (1.0 + std::exp(-cur_data[3]))) * 2, 2) * anchors[k][1];

          double xmin = (cx - ww / 2.0)* w_scale;
          double ymin = (cy - hh / 2.0)* h_scale;
          double xmax = (cx + ww / 2.0)* w_scale;
          double ymax = (cy + hh / 2.0)* h_scale;

          if (xmax <= 0 || ymax <= 0) { continue; }
          if (xmin > xmax || ymin > ymax) { continue; }
          if (xmin < 0) { xmin = 0;}
          if (ymin < 0) { ymin = 0;}
          if (xmax >= ori_shape[1]) { xmax = ori_shape[1]-1;}
          if (ymax >= ori_shape[0]) { ymax = ori_shape[0]-1;}

          boxs.emplace_back(cv::Rect(xmin, ymin, xmax-xmin, ymax-ymin));
          scores.emplace_back((float)confidence);
          labels.emplace_back(id);
        }
        data = data + num_pred * anchors.size();
      }
    }
}


// int RKDetPredictor::get_tensor_hw(hbDNNTensor* tensor, int *height, int *width) {
//   int h_index = 0;
//   int w_index = 0;
//   if (tensor->properties.tensorLayout == HB_DNN_LAYOUT_NHWC) {
//     h_index = 1;
//     w_index = 2;
//   }
//   else if (tensor->properties.tensorLayout == HB_DNN_LAYOUT_NCHW) {
//     h_index = 2;
//     w_index = 3;
//   }
//   else { return -1; }
//   *height = tensor->properties.validShape.dimensionSize[h_index];
//   *width = tensor->properties.validShape.dimensionSize[w_index];
//   return 0;
// }


}  // namespace hb
